NLLLossGrad

NLLLoss 的反向:由上游损失梯度反传得到对 logits / log_probs 的梯度。 仅在真实类别位置写入非零值,其余类别位置为 0。

设 batch 为 \(N\),类别数为 \(C\)logits / logits_grad 形状为 \(N \times C\)labels 长度为 \(N\)weight 长度为 \(C\)logits 仅占位,计算不读其数值。

对样本 \(i\),令 \(y_i = \mathrm{labels}[i]\)\(w_i = \mathrm{weight}[y_i]\)\(W = \mathrm{total\_weight}\)。先将 logits_grad 清零,再写:

\[\begin{split}\mathrm{logits\_grad}[i, y_i] = \begin{cases} -\,\mathrm{loss\_grad}[0] \cdot w_i, & \mathrm{reduction}=0\ \text{(Sum)} \\ -\,\mathrm{loss\_grad}[0] \cdot w_i / W, & \mathrm{reduction}=1\ \text{(Mean)} \\ -\,\mathrm{loss\_grad}[i] \cdot w_i, & \mathrm{reduction}=2\ \text{(None)} \end{cases}\end{split}\]

reduction_type 约定(本算子编码,与前向 NLLLoss 不同):

  • 0:Sum,使用标量 loss_grad[0]

  • 1:Mean,使用标量 loss_grad[0]total_weight

  • 2:None,使用逐样本 loss_grad[i]

输入:
  • logits - 前向输入地址,形状 [batch, class_num],不参与数值计算

  • loss_grad - 上游梯度;Sum / Mean 时用 loss_grad[0],None 时长度为 batch

  • labels - 标签索引,形状 [batch]

  • params - long long 参数数组,长度至少 5,布局见下

  • core_mask - 核掩码(仅共享存储版本使用)

params 布局:

  • [0] weight - 类别权重数组地址

  • [1] total_weight - 权重和地址,Mean 时使用

  • [2] batch - batch 大小 \(N\)

  • [3] class_num - 类别数 \(C\)

  • [4] reduction_type - 归约方式,取值 {0,1,2}

输出:
  • logits_grad - 输出梯度,形状 [batch, class_num]

支持平台:

FT78NE MT7004

备注

  • FT78NE 支持 fp32

  • MT7004 支持 fp16、fp32

  • labels[i] 需满足 \(0 \le y_i < C\)

  • 本算子 reduction_type0/1/2,即 Sum / Mean / None;与前向 NLLLoss0/1/2,即 None / Sum / Mean 不一致,调用时勿混用

共享存储版本:

void hp_nll_loss_grad_s(float16 *logits, float16 *loss_grad, int *labels, float16 *logits_grad, long long *params, int core_mask)
void fp_nll_loss_grad_s(float *logits, float *loss_grad, int *labels, float *logits_grad, long long *params, int core_mask)

C调用示例:

 1// MT7004 示例(共享存储多核,DDR 地址)
 2void TestNllLossGradSMCFp32(int core_mask) {
 3    int core_id = get_core_id();
 4    int logic_core_id = GetLogicCoreId(core_mask, core_id);
 5    int core_num = GetCoreNum(core_mask);
 6    float *logits = (float *)0x81000000;
 7    float *loss_grad = (float *)0x82000000;
 8    int *labels = (int *)0x83000000;
 9    float *weight = (float *)0x84000000;
10    float *total_weight = (float *)0x85000000;
11    float *logits_grad = (float *)0x86000000;
12    long long params[5];
13    params[0] = (long long)weight;
14    params[1] = (long long)total_weight;
15    params[2] = 16; // batch
16    params[3] = 16; // class_num
17    params[4] = 2;  // reduction_type = None
18    sys_bar(0, core_num);
19    fp_nll_loss_grad_s(logits, loss_grad, labels, logits_grad, params, core_mask);
20}
21
22void main() {
23    int core_mask = 0b1111;
24    TestNllLossGradSMCFp32(core_mask);
25}

私有存储版本:

void hp_nll_loss_grad_p(float16 *logits, float16 *loss_grad, int *labels, float16 *logits_grad, long long *params)
void fp_nll_loss_grad_p(float *logits, float *loss_grad, int *labels, float *logits_grad, long long *params)

C调用示例:

 1// MT7004 示例(私有存储单核,AM 地址)
 2void TestNllLossGradAMFp32(void) {
 3    float *logits = (float *)0x10010000;
 4    float *loss_grad = (float *)0x10020000;
 5    int *labels = (int *)0x10030000;
 6    float *weight = (float *)0x10040000;
 7    float *total_weight = (float *)0x10050000;
 8    float *logits_grad = (float *)0x10060000;
 9    long long params[5];
10    params[0] = (long long)weight;
11    params[1] = (long long)total_weight;
12    params[2] = 16; // batch
13    params[3] = 16; // class_num
14    params[4] = 2;  // reduction_type = None
15    fp_nll_loss_grad_p(logits, loss_grad, labels, logits_grad, params);
16}
17
18void main() {
19    TestNllLossGradAMFp32();
20}